﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media.Media3D;

namespace TeaStlShow
{
    public class CurveSmoother
    {
        // Catmull-Rom插值函数
        public  Point3D CatmullRomInterpolate(Point3D p0, Point3D p1, Point3D p2, Point3D p3, double t)
        {
            double t2 = t * t;
            double t3 = t2 * t;

            double x = 0.5 * ((2 * p1.X) +
                (-p0.X + p2.X) * t +
                (2 * p0.X - 5 * p1.X + 4 * p2.X - p3.X) * t2 +
                (-p0.X + 3 * p1.X - 3 * p2.X + p3.X) * t3);

            double y = 0.5 * ((2 * p1.Y) +
                (-p0.Y + p2.Y) * t +
                (2 * p0.Y - 5 * p1.Y + 4 * p2.Y - p3.Y) * t2 +
                (-p0.Y + 3 * p1.Y - 3 * p2.Y + p3.Y) * t3);

            double z = 0.5 * ((2 * p1.Z) +
                (-p0.Z + p2.Z) * t +
                (2 * p0.Z - 5 * p1.Z + 4 * p2.Z - p3.Z) * t2 +
                (-p0.Z + 3 * p1.Z - 3 * p2.Z + p3.Z) * t3);

            return new Point3D(x, y, z);
        }

        // Catmull-Rom切线（导数）
        public  Vector3D CatmullRomTangent(Point3D p0, Point3D p1, Point3D p2, Point3D p3, double t)
        {
            double t2 = t * t;

            double x = 0.5 * ((-p0.X + p2.X) +
                2 * (2 * p0.X - 5 * p1.X + 4 * p2.X - p3.X) * t +
                3 * (-p0.X + 3 * p1.X - 3 * p2.X + p3.X) * t2);

            double y = 0.5 * ((-p0.Y + p2.Y) +
                2 * (2 * p0.Y - 5 * p1.Y + 4 * p2.Y - p3.Y) * t +
                3 * (-p0.Y + 3 * p1.Y - 3 * p2.Y + p3.Y) * t2);

            double z = 0.5 * ((-p0.Z + p2.Z) +
                2 * (2 * p0.Z - 5 * p1.Z + 4 * p2.Z - p3.Z) * t +
                3 * (-p0.Z + 3 * p1.Z - 3 * p2.Z + p3.Z) * t2);

            Vector3D tangent = new Vector3D(x, y, z);
            tangent.Normalize();
            return tangent;
        }

        // 计算输入点的切线（差分法）
        public  List<Vector3D> CalculateInputTangents(List<Point3D> pts)
        {
            int n = pts.Count;
            List<Vector3D> tangents = new List<Vector3D>(n);

            for (int i = 0; i < n; i++)
            {
                Vector3D tangent;
                if (i == 0)
                {
                    tangent = pts[1] - pts[0];
                }
                else if (i == n - 1)
                {
                    tangent = pts[n - 1] - pts[n - 2];
                }
                else
                {
                    tangent = pts[i + 1] - pts[i - 1];
                }
                tangent.Normalize();
                tangents.Add(tangent);
            }
            return tangents;
        }

        // 主函数：输入点集和法线集，输出平滑点集、平滑切线集，和输入点切线集
        public  void SmoothCurveWithNormals(
            List<Point3D> pts,
            List<Vector3D> normals,
            int segments,
            out List<Point3D> smoothPts,
            out List<Vector3D> smoothTangents,
            out List<Vector3D> inputTangents)
        {
            if (pts == null || normals == null || pts.Count != normals.Count)
                throw new ArgumentException("点集和法线集不能为空且数量必须相等");

            smoothPts = new List<Point3D>();
            smoothTangents = new List<Vector3D>();

            inputTangents = CalculateInputTangents(pts);

            int n = pts.Count;

            for (int i = 0; i < n - 1; i++)
            {
                Point3D p0 = i == 0 ? pts[i] : pts[i - 1];
                Point3D p1 = pts[i];
                Point3D p2 = pts[i + 1];
                Point3D p3 = (i + 2 < n) ? pts[i + 2] : pts[i + 1];

                for (int j = 0; j <= segments; j++)
                {
                    double t = j / (double)segments;
                    Point3D pt = CatmullRomInterpolate(p0, p1, p2, p3, t);
                    Vector3D tangent = CatmullRomTangent(p0, p1, p2, p3, t);

                    smoothPts.Add(pt);
                    smoothTangents.Add(tangent);
                }
            }
        }
    }
}
